package com.ruoyi.point.watcher.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.point.pojo.SessionPermissions;
import com.ruoyi.framework.pojo.VirInfo;
import com.ruoyi.point.service.ISessionPermissionsService;
import com.ruoyi.framework.point.PointTable;
import com.ruoyi.framework.watcher.IWatcher;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.TimeUnit;


@Component
public class SessionPermissionsWatcher implements IWatcher {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper().registerModule(new JavaTimeModule());

    @Autowired
    private ISessionPermissionsService sessionPermissionsService;


    @Autowired
    private RedisCache redisCache;

    @Autowired
    private PointTable pointTable;

    private static final String NAME_INFO = "SessionPermissions";
    @PostConstruct
    public void init() {
        pointTable.addReadWatcher(NAME_INFO,this);
        pointTable.addWriteWatcher(NAME_INFO,this);
    }

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    @Override
    @Async
    public List<? extends VirInfo> selectPointInfo(String key, String parameter, Object value) {
        String parameters = parameter.replace("$", "");
        if (parameters.equals("all")){
            return sessionPermissionsService.selectSessionPermissionsList(null);
        } else {
            SessionPermissions sessionPermissions = new SessionPermissions();
            try {
                BeanUtils.setProperty(sessionPermissions,parameters,value);
                return sessionPermissionsService.selectSessionPermissionsList(sessionPermissions);
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    @Async
    public void updatePointTableValue(String key, Object value) {
        JsonNode jsonObject = null;
        String[] split = key.split("\\.");
        String id = split[1].replace("$", "");
        try {
            if (id.equals("add")) {
                jsonObject = OBJECT_MAPPER.readTree(String.valueOf(value));
                SessionPermissions sessionPermissions = OBJECT_MAPPER.readValue(jsonObject.traverse(), SessionPermissions.class);
                sessionPermissionsService.insertSessionPermissions(sessionPermissions);
                return;
            }
            if (sessionPermissionsService.selectSessionPermissionsByHasPowerInfo(2L) > 0 && redisCache.getCacheObject("Scepter") != null){
                throw new RuntimeException("There are already staff of the scepter");
            } else if (sessionPermissionsService.selectSessionPermissionsByHasPowerInfo(2L) > 0 && redisCache.getCacheObject("Scepter") == null) {
                sessionPermissionsService.updateSessionPermissionsByHasPowerInfo(2L);
                throw new RuntimeException("You no longer have permission, please reapply");
            }
            String nowTime = split[2];
            SessionPermissions sessionPermissions = sessionPermissionsService.selectSessionPermissionsById(Long.valueOf(id));
            if (nowTime.equals("time") && sessionPermissions.getHasPowerInfo() == 1) {
                String substring = value.toString().substring(1, value.toString().length() - 1);
                LocalDateTime now = LocalDateTime.parse(substring, formatter);
                LocalDateTime allowTheScepterToGetTheStartTime = sessionPermissions.getAllowTheScepterToGetTheStartTime();
                LocalDateTime allowTheScepterToGetTheEndTime = sessionPermissions.getAllowTheScepterToGetTheEndTime();
                if (now.isAfter(allowTheScepterToGetTheStartTime) && now.isBefore(allowTheScepterToGetTheEndTime)){
                    sessionPermissionsService.updateSessionPermissions(SessionPermissions.builder().id(Long.valueOf(id)).userId(sessionPermissions.getUserId()).hasPowerInfo(2L).build());
                    Duration duration = Duration.between(now,allowTheScepterToGetTheEndTime);
                    redisCache.setCacheObject("Scepter", sessionPermissions.getUserId(), (int) duration.getSeconds(), TimeUnit.SECONDS);
                    return;
                } else {
                    throw new RuntimeException("Not within the time of application for the scepter or has expired");
                }
            } else if (nowTime.equals("time") && sessionPermissions.getHasPowerInfo() == 0){
                throw new RuntimeException("Your permission is disabled and cannot be applied.");
            }
            if (sessionPermissions != null) {
                try {
                    if (value == "1" && sessionPermissions.getHasPowerInfo() == 2){
                        redisCache.deleteObject("Scepter");
                    }
                    BeanUtils.setProperty(sessionPermissions,nowTime,value);
                    sessionPermissionsService.updateSessionPermissions(sessionPermissions);
                    return;
                } catch (IllegalAccessException | InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            }
        } catch (ArrayIndexOutOfBoundsException | IOException e){
            try {
                OBJECT_MAPPER.registerModule(new JavaTimeModule());
                jsonObject = OBJECT_MAPPER.readTree(value.toString());
                SessionPermissions sessionPermissions = OBJECT_MAPPER.readValue(jsonObject.traverse(), SessionPermissions.class);
                sessionPermissions.setId(Long.valueOf(id));
                sessionPermissionsService.updateSessionPermissions(sessionPermissions);
                return;
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
        throw new RuntimeException("ID does not exist");
    }
}
